package com.my.study.pool.mypool;

import lombok.extern.slf4j.Slf4j;

import java.util.HashSet;
import java.util.concurrent.TimeUnit;

/**
 * @author Carlos
 * @version 1.0
 * @Description 线程池
 * @date 2021/6/10 8:10
 **/
@Slf4j(topic = "c.ThreadPool")
public class ThreadPool {

    /**
     * 工作/任务队列
     */
    private final BlockQueue<Runnable> workQueue;

    /**
     * 线程集合
     */
    private final HashSet<Worker> workers = new HashSet();

    /**
     * 核心线程数
     */
    private int coreSize;

    /**
     * 获取任务的超时时间
     */
    private long timeout;

    /**
     * 时间单位
     */
    private TimeUnit timeUnit;

    /**
     * 拒绝策略
     */
    private RejectPolicy<Runnable> rejectPolicy;


    public ThreadPool(int coreSize, long timeout, TimeUnit timeUnit, int queueCapacity, RejectPolicy rejectPolicy) {
        this.coreSize = coreSize;
        this.timeout = timeout;
        this.timeUnit = timeUnit;
        this.rejectPolicy = rejectPolicy;
        this.workQueue = new BlockQueue<>(queueCapacity);
    }


    public void execute(Runnable task) {
        synchronized (workers) {
            if (workers.size() < coreSize) {
                Worker worker = new Worker(task);
                log.debug("新增 worker: {}, task: {}", worker, task);
                workers.add(worker);
                worker.start();
            } else {
                workQueue.tryPut(rejectPolicy, task);
            }
        }
    }


    final class Worker extends Thread{

        private Runnable task;

        public Worker(Runnable task) {
            this.task = task;
        }

        @Override
        public void run() {
            // 执行任务
            // 1、当task不为空时，执行task任务
            // 2、当task为空时，从队列workQueue获取任务执行
            // 3、
            while (task != null || (task = workQueue.poll(timeout, timeUnit)) != null) {
                try {
                    log.debug("正在执行...{}", task);
                    task.run();
                } catch (Exception e) {
                } finally {
                    task = null;
                }
            }
            synchronized (workers) {
                log.debug("移除worker：{}", this);
                workers.remove(this);
            }

        }
    }

}
